package com.shop.shopmall.utils;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Random;

/**
 * 验证码工具类
 */
public class ValidCodeUtil {

    // 验证码图片的宽
    private final int width;

    // 验证码图片的高
    private final int height;

    // 字体
    private final String[] fontNames;

    // 背景色
    private final Color bgColor;

    // 验证码
    private final String codes;

    // 随机数
    private final ThreadLocal<Random> random = ThreadLocal.withInitial(Random::new);

    // 验证码
    private transient String validCode;

    /**
     * 构造方法
     * @param width
     * @param height
     * @param fontNames
     * @param bgColor
     * @param codes
     */
    public ValidCodeUtil(int width, int height, String[] fontNames, Color bgColor, String codes) {
        this.width = width;
        this.height = height;
        this.fontNames = fontNames != null ? fontNames : new String[]{"宋体", "楷体", "隶书", "微软雅黑"};
        this.bgColor = bgColor != null ? bgColor : Color.WHITE;
        this.codes = codes != null ? codes : "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
    }

    /**
     * 随机颜色
     * @return
     */
    private Color getColor() {
        int red = random.get().nextInt(200);
        int green = random.get().nextInt(200);
        int blue = random.get().nextInt(200);
        return new Color(red, green, blue);
    }

    /**
     * 随机字体
     * @return
     */
    private Font getFont() {
        String name = fontNames[random.get().nextInt(fontNames.length)];
        int style = random.get().nextInt(4); // 0-PLAIN, 1-BOLD, 2-ITALIC, 3-BOLD+ITALIC
        int size = random.get().nextInt(8) + 20; // 字体大小范围调整为20-28
        return new Font(name, style, size);
    }

    /**
     * 随机字符
     * @return
     */
    private char getChar() {
        return codes.charAt(random.get().nextInt(codes.length()));
    }

    /**
     * 创建图片
     * @return
     */
    private BufferedImage createImage() {
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2 = image.createGraphics();
        g2.setColor(bgColor);
        g2.fillRect(0, 0, width, height);
        return image;
    }

    /**
     * 获取图片
     * @return
     */
    public BufferedImage getImage() {
        BufferedImage image = createImage();
        Graphics2D g2 = image.createGraphics();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < 4; i++) {
            String s = getChar() + "";
            sb.append(s);
            g2.setColor(getColor());
            g2.setFont(getFont());
            // 确保字符不重叠，调整绘制位置
            FontMetrics metrics = g2.getFontMetrics();
            float x = i * width * 1.0f / 4;
            float adjustX = (width / 4 - metrics.stringWidth(s)) / 2;
            g2.drawString(s, x + adjustX, height - 15);
        }
        this.validCode = sb.toString();
        drawLine(g2);
        g2.dispose();
        return image;
    }

    /**
     * 绘制干扰线
     * @param g2
     */
    private void drawLine(Graphics2D g2) {
        int num = 8; // 增加干扰线数量以提高难度
        for (int i = 0; i < num; i++) {
            int x1 = random.get().nextInt(width);
            int y1 = random.get().nextInt(height);
            int x2 = random.get().nextInt(width);
            int y2 = random.get().nextInt(height);
            g2.setColor(getColor());
            g2.setStroke(new BasicStroke(1.5f));
            g2.drawLine(x1, y1, x2, y2);
        }
    }

    /**
     * 输出图片
     * @param image
     * @param out
     * @throws IOException
     */
    public static void output(BufferedImage image, OutputStream out) throws IOException {
        ImageIO.write(image, "JPEG", out);
    }

    public String getValidCode() {
        return validCode;
    }

}